package cn.blnp.net.flowable.boot.demo.controller;

import cn.blnp.net.flowable.boot.demo.bean.common.ResponseListDto;
import cn.blnp.net.flowable.boot.demo.bean.model.NewModelDto;
import cn.blnp.net.flowable.boot.demo.bean.model.SaveModelDto;
import cn.blnp.net.flowable.boot.demo.entity.ActDeModelEntity;
import cn.blnp.net.flowable.boot.demo.repository.ActDeModelRepository;
import cn.blnp.net.flowable.boot.service.TaskRecallService;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.filter.SimplePropertyPreFilter;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricActivityInstanceQuery;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ExecutionQuery;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * <h3></h3>
 *
 * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
 * @version 1.0
 * @since 2025/5/26 16:36
 */
@Slf4j
@RestController
@RequestMapping
public class DemoController {

    @Resource
    private ActDeModelRepository actDeModelRepository;
    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private IdentityService identityService;
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;
    @Resource
    private TaskRecallService taskRecallService;

    ObjectMapper objectMapper = new ObjectMapper();
    SimplePropertyPreFilter taskFilter = new SimplePropertyPreFilter(Task.class,
            "id", "name", "executionId", "taskDefinitionKey");
    SimplePropertyPreFilter executionFilter = new SimplePropertyPreFilter(Execution.class,
            "id", "parentId", "processInstanceId", "activityId", "isScope");
    SimplePropertyPreFilter historicActivityFilter =
            new SimplePropertyPreFilter(HistoricActivityInstance.class,
                    "id", "activityId", "activityName", "taskId");

    @GetMapping("/list")
    public ResponseListDto<ActDeModelEntity> hello(HttpServletRequest request) {
        int current = 1;
        int pageSize = 10;
        try {
            String curStr = request.getParameter("current");
            if (StringUtils.isNotEmpty(curStr)) {
                current = Integer.parseInt(curStr);
            }
            String pageSizeStr = request.getParameter("pageSize");
            if (StringUtils.isNotEmpty(pageSizeStr)) {
                pageSize = Integer.parseInt(pageSizeStr);
            }
        } catch (Exception e) {
            log.warn("parse parameter error!");
        }
        int page = Math.max(0, current - 1);
        ResponseListDto<ActDeModelEntity> responseListDto = new ResponseListDto<>();
        long total = actDeModelRepository.count();
        responseListDto.setTotal(total);
        if (total > 0) {
            Page<ActDeModelEntity> list = actDeModelRepository.findAll(PageRequest.of(page, pageSize));
            responseListDto.setData(list.getContent());
        }
        return responseListDto;
    }

    @PostMapping("/add")
    public String newModel(@RequestBody NewModelDto newModelDto) throws Exception {
        String modelKey = newModelDto.getModelKey();
        if (StringUtils.isEmpty(modelKey)) {
            throw new Exception("缺少必填内容：表单模型key");
        }
        List<ActDeModelEntity> result = actDeModelRepository.findModelsByKeyAndType(modelKey, ActDeModelEntity.MODEL_TYPE_FORM);
        if (result != null && result.size() > 0) {
            throw new Exception("重复性校验不通过：表单模型key已存在");
        }
        ActDeModelEntity newModel = new ActDeModelEntity();
        newModel.setName(newModelDto.getModelName());
        newModel.setKey(newModelDto.getModelKey());
        newModel.setDescription(newModelDto.getDescription());
        newModel.setModelType(ActDeModelEntity.MODEL_TYPE_FORM);
        newModel.setCreatedBy("huhaiqin");
        newModel.setLastUpdatedBy("huhaiqin");
        newModel.setModelEditorJson("{}");
        ActDeModelEntity model = actDeModelRepository.save(newModel);
        return model.getId();
    }

    @GetMapping("/detail/{modelId}")
    public String getDetail(@PathVariable("modelId") String modelId) throws Exception {
        Optional<ActDeModelEntity> result = actDeModelRepository.findById(modelId);
        if (result.isPresent()) {
            ActDeModelEntity model = result.get();
            String modelJson = model.getModelEditorJson();
            Map<String, Object> fieldMap = objectMapper.readValue(modelJson,
                    new TypeReference<Map<String, Object>>() {
                    });
            Map<String, Object> formMap = new HashMap<>();
            formMap.put("type", "object");
            formMap.put("displayType", "row");
            formMap.put("properties", fieldMap);
            return objectMapper.writeValueAsString(formMap);
        }
        return "{}";
    }

    @DeleteMapping("/delete/{modelId}")
    public void deleteModel(@PathVariable("modelId") String modelId) {
        actDeModelRepository.deleteById(modelId);
    }

    @PostMapping("/save")
    public String saveModel(@RequestBody SaveModelDto saveModelDto) throws Exception {
        Optional<ActDeModelEntity> result = actDeModelRepository.findById(saveModelDto.getModelId());
        if (!result.isPresent()) {
            throw new Exception("表单模型不存在");
        }
        ActDeModelEntity model = result.get();
        model.setModelEditorJson(saveModelDto.getModelJson());
        model.setLastUpdatedBy("huhaiqin");
        model.setLastUpdated(new Date());
        actDeModelRepository.save(model);
        return "success";
    }

    @GetMapping("/start")
    public String startProcess() throws InterruptedException {
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("flow/taskRecallProcess.bpmn20.xml")
                .name("流程任务撤回案例演示")
                .deploy();
        log.info("部署ID：{}", deploy.getId());
        //流程定义信息
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .singleResult();
        log.info("流程定义ID：{}", processDefinition.getId());
        //启动流程实例
        ProcessInstance procInst = runtimeService.startProcessInstanceById(processDefinition.getId());
        log.info("流程实例ID：{}", procInst.getId());
        TaskQuery taskQuery = taskService.createTaskQuery()
                .processInstanceId(procInst.getId());
        ExecutionQuery executionQuery = runtimeService.createExecutionQuery()
                .processInstanceId(procInst.getId());
        HistoricActivityInstanceQuery hisActivityQuery = historyService
                .createHistoricActivityInstanceQuery()
                .processInstanceId(procInst.getId());

        //查询借款申请用户任务的task
        Task firstTask = taskQuery.singleResult();
        //完成借款申请用户任务的task
        taskService.complete(firstTask.getId());
        //进行休眠等待
        Thread.sleep(50*1000);
        log.info("撤回前，当前任务为：{}", JSON.toJSONString(taskQuery.list(), taskFilter));
        log.info("当前执行实例有：{}", JSON.toJSONString(executionQuery.list(), executionFilter));
        log.info("历史节点实例有：{}", JSON.toJSONString(hisActivityQuery.list(), historicActivityFilter));

        //执行撤回操作
        taskRecallService.executeRecall(firstTask.getId());

        log.info("撤回后，当前任务为：{}", JSON.toJSONString(taskQuery.list(), taskFilter));
        log.info("当前执行实例有：{}", JSON.toJSONString(executionQuery.list(), executionFilter));
        log.info("历史节点实例有：{}", JSON.toJSONString(hisActivityQuery.list(), historicActivityFilter));
        return "success";
    }
}
